module MxQueue(
	
	input			i_MQ_clk,
	input			i_MQ_enable,
	input			i_MQ_reset,
	//Stall
	output			o_MQ_stall,
	input			i_MQ_IssueStall,
	//PhyRegState
	input	[63:0]	i_MQ_PhyRegState,
	//EnQueue
	input	[64:0]	i_MQ_VIP1,		//{[64]valid, [63:32]Inst, [31:0]PC}
	input	[11:0]	i_MQ_PRSrc1,	//{[11:6]pregsrc1, [5:0]pregsrc2}
	input	[16:0]	i_MQ_PRDes1,	//{[16:12]regdes, [11:6]pregdes, [5:0]ppregdes}
	input	[29:0]	i_MQ_IDcode1,	//{[29:25]alcode, [24:20]bjcode, [19:15]iecode, [14:10]mvcode, [9:5]mdcode, [4:0]memcode}			
	input	[7:0]	i_MQ_EXCCODE1,
	input	[5:0]	i_MQ_ReOrderNum1,
	input	[64:0]	i_MQ_VIP2,		
	input	[11:0]	i_MQ_PRSrc2,	
	input	[16:0]	i_MQ_PRDes2,	
	input	[29:0]	i_MQ_IDcode2,
	input	[7:0]	i_MQ_EXCCODE2,
	input	[5:0]	i_MQ_ReOrderNum2,
	//DeQueue
	output	[64:0]	o_MQ_VIP,		//{[64]valid, [63:32]Inst, [31:0]PC}
	output	[11:0]	o_MQ_PRSrc,		//{[11:6]pregsrc1, [5:0]pregsrc2}
	output	[16:0]	o_MQ_PRDes,		//{[16:12]regdes, [11:6]pregdes, [5:0]ppregdes}
	output	[29:0]	o_MQ_IDcode,	//{[29:25]alcode, [24:20]bjcode, [19:15]iecode, [14:10]mvcode, [9:5]mdcode, [4:0]memcode}			
	output	[7:0]	o_MQ_EXCCODE,
	output	[5:0]	o_MQ_ReOrderNum,
	//COMMIT
	input			I_MQ_CMTrollback

);

	reg			valid[15:0]
	reg	[5:0]	pregrc1[15:0];
	reg	[5:0]	pregrc2[15:0];
	//follow
	reg	[63:0]	InstPC[15:0];
	reg	[16:0]	PRDes[15:0];
	reg	[29:0]	IDcode[15:0];
	reg	[7:0]	EXCCODE[15:0];
	reg	[5:0]	ReOrderNum[15:0];
	
	reg		[3:0]	EnQueuePointer;
	reg		[3:0]	DeQueuePointer;
	
	//EnQueue
	wire	[15:0]	EmptyList;
	begin:	emptylist
		reg	[7:0]	tempI;
		for(tempI=8'd0; tempI<=8'd15; tempI=tempI+8'd1)
			assign	EmptyList[tempI[3:0]] = ~valid[tempI[3:0]];
	end
	wire	Empty = (EmptyList==16'hffff);
	
	wire	match1 = i_MQ_VIP1[64] && (i_MQ_IDcode1[14:5]!=10'd0);
	wire	match2 = i_MQ_VIP2[64] && (i_MQ_IDcode2[14:5]!=10'd0);
	
	assign	o_MQ_stall = ~Empty &&
						 (((DeQueuePointer==EnQueuePointer) && (match1 || match) ||
						  ((DeQueuePointer==EnQueuePointer+4'd1) && match1 && match2));
	//DeQueue
	wire	Ready = valid[DeQueuePointer] && 
					i_MQ_PhyRegState[pregrc1[DeQueuePointer]];
					i_MQ_PhyRegState[pregrc2[DeQueuePointer]];
	assign	o_MQ_VIP		= (Ready) ? {valid[DeQueuePointer], InstPC[DeQueuePointer]}: 65'd0:
	assign	o_MQ_PRSrc		= (Ready) ? {pregrc1[DeQueuePointer], pregrc2[DeQueuePointer]}: 12'd0:
	assign	o_MQ_PRDes	 	= (Ready) ? PRDes[DeQueuePointer]: 17'd0:
	assign	o_MQ_IDcode	 	= (Ready) ? IDcode[DeQueuePointer]: 30'd0:
	assign	o_MQ_EXCCODE	 	= (Ready) ? EXCCODE[DeQueuePointer]: 8'd0:
	assign	o_MQ_ReOrderNum = (Ready) ? ReOrderNum[DeQueuePointer]: 6'd0:

always @(posedge i_MQ_clk)
	begin
		if(i_MQ_reset)
			begin:	reset
				reg	[7:0]	tempJ;
				for(tempJ=8'd0; tempJ<=8'd15; tempJ=tempJ+8'd1)
					begin
						valid[tempJ[3:0]]		<= 1'd0;
						pregrc1[tempJ[3:0]]		<= 6'd0;
						pregrc2[tempJ[3:0]]		<= 6'd0;
						InstPC[tempJ[3:0]]		<= 64'd0;
						PRDes[tempJ[3:0]]		<= 17'd0;
						IDcode[tempJ[3:0]]		<= 30'd0;
						EXCCODE[tempJ[3:0]]		<= 8'd0;
						ReOrderNum[tempJ[3:0]]	<= 6'd0;
						//Pointers
						DeQueuePointer	<= 4'd0;
						EnQueuePointer  <= 4'd0;
					end
			end
		else if(i_MQ_enable)
			begin
				if(I_MQ_CMTrollback)
					begin
						//rollback
						reg	[7:0]	tempK;
						for(tempK=8'd0; tempK<=8'd15; tempK=tempK+8'd1)
							begin
							valid[tempK[3:0]]		<= 1'd0;
							pregrc1[tempK[3:0]]		<= 6'd0;
							pregrc2[tempK[3:0]]		<= 6'd0;
							InstPC[tempK[3:0]]		<= 64'd0;
							PRDes[tempK[3:0]]		<= 17'd0;
							IDcode[tempK[3:0]]		<= 30'd0;
							EXCCODE[tempK[3:0]]		<= 8'd0;
							ReOrderNum[tempK[3:0]]	<= 6'd0;
							//Pointers
							DeQueuePointer	<= 4'd0;
							EnQueuePointer  <= 4'd0;
						end
					end
				else
					begin
						//EnQueue
						if(~o_MQ_stall && match1 && match2)
							begin
								valid[EnQueuePointer]		<= i_MQ_VIP1[64];
								pregrc1[EnQueuePointer]		<= i_MQ_PRSrc1[11:6];
								pregrc2[EnQueuePointer]		<= i_MQ_PRSrc1[5:0];
								InstPC[EnQueuePointer]		<= i_MQ_VIP1[63:0];
								PRDes[EnQueuePointer]		<= i_MQ_PRDes1;
								IDcode[EnQueuePointer]		<= i_MQ_IDcode1;
								EXCCODE[EnQueuePointer]		<= i_MQ_EXCCODE1;
								ReOrderNum[EnQueuePointer]	<= i_MQ_ReOrderNum1;
								
								valid[EnQueuePointer+4'd1]		<= i_MQ_VIP2[64];
								pregrc1[EnQueuePointer+4'd1]	<= i_MQ_PRSrc2[11:6];
								pregrc2[EnQueuePointer+4'd1]	<= i_MQ_PRSrc2[5:0];
								InstPC[EnQueuePointer+4'd1]		<= i_MQ_VIP2[63:0];
								PRDes[EnQueuePointer+4'd1]		<= i_MQ_PRDes2;
								IDcode[EnQueuePointer+4'd1]		<= i_MQ_IDcode2;
								EXCCODE[EnQueuePointer+4'd1]		<= i_MQ_EXCCODE2;
								ReOrderNum[EnQueuePointer+4'd1]	<= i_MQ_ReOrderNum2;
								//updata EnQueuePointer
								EnQueuePointer <= EnQueuePointer + 4'd2;
							end
						if(~o_MQ_stall && match1 && ~match2)
							begin
								valid[EnQueuePointer]		<= i_MQ_VIP1[64];
								pregrc1[EnQueuePointer]		<= i_MQ_PRSrc1[11:6];
								pregrc2[EnQueuePointer]		<= i_MQ_PRSrc1[5:0];
								InstPC[EnQueuePointer]		<= i_MQ_VIP1[63:0];
								PRDes[EnQueuePointer]		<= i_MQ_PRDes1;
								IDcode[EnQueuePointer]		<= i_MQ_IDcode1;
								EXCCODE[EnQueuePointer]		<= i_MQ_EXCCODE1;
								ReOrderNum[EnQueuePointer]	<= i_MQ_ReOrderNum1;
								//updata EnQueuePointer
								EnQueuePointer <= EnQueuePointer + 4'd1;
							end
						if(~o_MQ_stall && ~match1 && match2)
							begin
								valid[EnQueuePointer]		<= i_MQ_VIP2[64];
								pregrc1[EnQueuePointer]		<= i_MQ_PRSrc2[11:6];
								pregrc2[EnQueuePointer]		<= i_MQ_PRSrc2[5:0];
								InstPC[EnQueuePointer]		<= i_MQ_VIP2[63:0];
								PRDes[EnQueuePointer]		<= i_MQ_PRDes2;
								IDcode[EnQueuePointer]		<= i_MQ_IDcode2;
								EXCCODE[EnQueuePointer]		<= i_MQ_EXCCODE2;
								ReOrderNum[EnQueuePointer]	<= i_MQ_ReOrderNum2;
								//updata EnQueuePointer
								EnQueuePointer <= EnQueuePointer + 4'd1;
							end
						if(~i_MQ_IssueStall && Ready)
							begin
								//DeQueue
								valid[DeQueuePointer]		<= 1'd0;
								pregrc1[DeQueuePointer]		<= 6'd0;
								pregrc2[DeQueuePointer]		<= 6'd0;
								InstPC[DeQueuePointer]		<= 64'd0;
								PRDes[DeQueuePointer]		<= 17'd0;
								IDcode[DeQueuePointer]		<= 30'd0;
								EXCCODE[DeQueuePointer]		<= 8'd0;
								ReOrderNum[DeQueuePointer]	<= 6'd0;
								//updata DeQueuePointer
								DeQueuePointer <= DeQueuePointer + 4'd1;
							end
					end
			end
	end


endmodule